#include "Rp2VertexBuffer.h"

using namespace Rp2;

//---------------------------------------------------------------------------------------------------
VertexBuffer::VertexBuffer(const Attributes& rkAttr, int iVertexQuantity)
	:
	m_kAttributes(rkAttr)
{
	assert(iVertexQuantity > 0);
	m_iVertexSize = rkAttr.GetChannelQuantity();
	m_iVertexQuantity = iVertexQuantity;
	m_iDataSize = m_iVertexSize * m_iVertexQuantity;
	m_afData = new float[m_iDataSize];
	memset(m_afData, 0, m_iDataSize * sizeof(float));
}
//---------------------------------------------------------------------------------------------------
VertexBuffer::VertexBuffer(const VertexBuffer* pkVBuffer)
{
	assert(pkVBuffer);
	m_kAttributes = pkVBuffer->m_kAttributes;
	m_iVertexQuantity = pkVBuffer->m_iVertexQuantity;
	m_iVertexSize = m_kAttributes.GetChannelQuantity();
	m_iDataSize = m_iVertexQuantity * m_iVertexSize;
	m_afData = new float[m_iDataSize];
	memcpy(m_afData, pkVBuffer->m_afData, m_iDataSize * sizeof(float));
}
//---------------------------------------------------------------------------------------------------
VertexBuffer::~VertexBuffer()
{
    // Inform all renderers using this vertex buffer that it is being
    // destroyed.  This allows the renderer to free up any associated
    // resources.
	Release();

	delete[] m_afData;
}
//---------------------------------------------------------------------------------------------------
Vector3f& VertexBuffer::Position3(int i)
{
	assert(m_kAttributes.GetPositionChannels() == 3);
	int iIndex = m_iVertexSize * i + m_kAttributes.GetPositionOffset();
	return *(Vector3f*)(m_afData + iIndex);
}
//---------------------------------------------------------------------------------------------------
Vector3f VertexBuffer::Position3(int i) const
{
	assert(m_kAttributes.GetPositionChannels() == 3);
	int iIndex = m_iVertexSize * i + m_kAttributes.GetPositionOffset();
	return *(Vector3f*)(m_afData + iIndex);
}
//---------------------------------------------------------------------------------------------------
Vector3f& VertexBuffer::Normal3(int i)
{
	assert(m_kAttributes.GetNormalChannels() == 3);
	int iIndex = m_iVertexSize * i + m_kAttributes.GetNormalOffset();
	return *(Vector3f*)(m_afData + iIndex);
}
//---------------------------------------------------------------------------------------------------
Vector3f VertexBuffer::Normal3(int i) const
{
	assert(m_kAttributes.GetNormalChannels() == 3);
	int iIndex = m_iVertexSize * i + m_kAttributes.GetNormalOffset();
	return *(Vector3f*)(m_afData + iIndex);
}
//---------------------------------------------------------------------------------------------------
ColorRGB& VertexBuffer::Color3(int iUnit, int i)
{
	assert(m_kAttributes.GetColorChannels(iUnit) == 3);
	int iIndex = m_iVertexSize * i + m_kAttributes.GetColorOffset(iUnit);
	return *(ColorRGB*)(m_afData + iIndex);
}
//---------------------------------------------------------------------------------------------------
ColorRGB VertexBuffer::Color3(int iUnit, int i) const
{
	assert(m_kAttributes.GetColorChannels(iUnit) == 3);
	int iIndex = m_iVertexSize * i + m_kAttributes.GetColorOffset(iUnit);
	return *(ColorRGB*)(m_afData + iIndex);
}
//---------------------------------------------------------------------------------------------------
float& VertexBuffer::TCoord1 (int iUnit, int i)
{
    assert(m_kAttributes.GetTCoordChannels(iUnit) == 1);
    int iIndex = m_iVertexSize*i + m_kAttributes.GetTCoordOffset(iUnit);
    return *(m_afData + iIndex);
}
//---------------------------------------------------------------------------------------------------
float VertexBuffer::TCoord1 (int iUnit, int i) const
{
    assert(m_kAttributes.GetTCoordChannels(iUnit) == 1);
    int iIndex = m_iVertexSize*i + m_kAttributes.GetTCoordOffset(iUnit);
    return *(m_afData + iIndex);
}
//---------------------------------------------------------------------------------------------------
Vector2f& VertexBuffer::TCoord2 (int iUnit, int i)
{
    assert(m_kAttributes.GetTCoordChannels(iUnit) == 2);
    int iIndex = m_iVertexSize*i + m_kAttributes.GetTCoordOffset(iUnit);
    return *(Vector2f*)(m_afData + iIndex);
}
//---------------------------------------------------------------------------------------------------
Vector2f VertexBuffer::TCoord2 (int iUnit, int i) const
{
    assert(m_kAttributes.GetTCoordChannels(iUnit) == 2);
    int iIndex = m_iVertexSize*i + m_kAttributes.GetTCoordOffset(iUnit);
    return *(Vector2f*)(m_afData + iIndex);
}
//---------------------------------------------------------------------------------------------------
Vector4f& VertexBuffer::TCoord4(int iUnit, int i)
{
    assert(m_kAttributes.GetTCoordChannels(iUnit) == 4);
    int iIndex = m_iVertexSize*i + m_kAttributes.GetTCoordOffset(iUnit);
    return *(Vector4f*)(m_afData + iIndex);
}
//---------------------------------------------------------------------------------------------------
Vector4f VertexBuffer::TCoord4(int iUnit, int i) const
{
    assert(m_kAttributes.GetTCoordChannels(iUnit) == 4);
    int iIndex = m_iVertexSize*i + m_kAttributes.GetTCoordOffset(iUnit);
    return *(Vector4f*)(m_afData + iIndex);
}
//---------------------------------------------------------------------------------------------------
float* VertexBuffer::PositionTuple (int i)
{
    if (m_kAttributes.HasPosition() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetPositionOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
const float* VertexBuffer::PositionTuple (int i) const
{
    if (m_kAttributes.HasPosition() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetPositionOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
float* VertexBuffer::BlendWeightTuple (int i)
{
    if (m_kAttributes.HasBlendWeight() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetBlendWeightOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
const float* VertexBuffer::BlendWeightTuple (int i) const
{
    if (m_kAttributes.HasBlendWeight() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetBlendWeightOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
float* VertexBuffer::NormalTuple (int i)
{
    if (m_kAttributes.HasNormal() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetNormalOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
const float* VertexBuffer::NormalTuple (int i) const
{
    if (m_kAttributes.HasNormal() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetNormalOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
float* VertexBuffer::ColorTuple (int iUnit, int i)
{
    if (m_kAttributes.HasColor(iUnit) && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetColorOffset(iUnit);
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
const float* VertexBuffer::ColorTuple (int iUnit, int i) const
{
    if (m_kAttributes.HasColor(iUnit) && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetColorOffset(iUnit);
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
float* VertexBuffer::FogTuple (int i)
{
    if (m_kAttributes.HasFog() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetFogOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
const float* VertexBuffer::FogTuple (int i) const
{
    if (m_kAttributes.HasFog() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetFogOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
float* VertexBuffer::PSizeTuple (int i)
{
    if (m_kAttributes.HasPSize() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetPSizeOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
const float* VertexBuffer::PSizeTuple (int i) const
{
    if (m_kAttributes.HasPSize() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetPSizeOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
float* VertexBuffer::BlendIndicesTuple (int i)
{
    if (m_kAttributes.HasBlendIndices() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetBlendIndicesOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
const float* VertexBuffer::BlendIndicesTuple (int i) const
{
    if (m_kAttributes.HasBlendIndices() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetBlendIndicesOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
float* VertexBuffer::TCoordTuple (int iUnit, int i)
{
    if (m_kAttributes.HasTCoord(iUnit) && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetTCoordOffset(iUnit);
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
const float* VertexBuffer::TCoordTuple (int iUnit, int i) const
{
    if (m_kAttributes.HasTCoord(iUnit) && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetTCoordOffset(iUnit);
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
float* VertexBuffer::TangentTuple (int i)
{
    if (m_kAttributes.HasTangent() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetTangentOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
const float* VertexBuffer::TangentTuple (int i) const
{
    if (m_kAttributes.HasTangent() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetTangentOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
float* VertexBuffer::BitangentTuple (int i)
{
    if (m_kAttributes.HasBitangent() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetBitangentOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
const float* VertexBuffer::BitangentTuple (int i) const
{
    if (m_kAttributes.HasBitangent() && 0 <= i && i < m_iVertexQuantity)
    {
        int iIndex = m_iVertexSize*i + m_kAttributes.GetBitangentOffset();
        return m_afData + iIndex;
    }
    return 0;
}
//---------------------------------------------------------------------------------------------------
void VertexBuffer::CompactData(const Attributes& rkIAttr, bool bPackARGB, 
		int& riChannels, float*& rafOut) const
{
    // The use of "unsigned int" is to allow storage of "float" channels and
    // of the ARGB-formatted colors, which are "unsigned int".  Typecasting
    // "float" pointers to "unsigned int" pointers and then dereferencing
    // them works as expected.  The alternative is to use a vector of "float"
    // and typecast "unsigned int" pointers to "float" pointers.  However,
    // dereferencing to a "float" to allow push_back has problems.  The
    // memory pattern for an "unsigned int" might correspond to an invalid
    // "float".  The floating-point unit actually makes adjustments to these
    // values, changing what it is you started with.
    std::vector<unsigned int> kCompatible;    
    const unsigned int* puiData;
    float fOne = 1.0f;
    unsigned int* puiOne = (unsigned int*)&fOne;
    int iUnit, iIChannels, iVBChannels;

    for (int i = 0, j; i < m_iVertexQuantity; i++)
    {
        if (rkIAttr.HasPosition())
        {
            iIChannels = rkIAttr.GetPositionChannels();
            iVBChannels = m_kAttributes.GetPositionChannels();
            puiData = (unsigned int*)PositionTuple(i);
            if (iVBChannels < iIChannels)
            {
                for (j = 0; j < iVBChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
                for (j = iVBChannels; j < iIChannels; j++)
                {
                    // Fill with 1 so that the w-component is compatible with
                    // a homogeneous point.
                    kCompatible.push_back(*puiOne);
                }
            }
            else
            {
                for (j = 0; j < iIChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
            }
        }

        if (rkIAttr.HasBlendWeight())
        {
            iIChannels = rkIAttr.GetBlendWeightChannels();
            iVBChannels = m_kAttributes.GetBlendWeightChannels();
            puiData = (unsigned int*)BlendWeightTuple(i);
            if (iVBChannels < iIChannels)
            {
                for (j = 0; j < iVBChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
                for (j = iVBChannels; j < iIChannels; j++)
                {
                    kCompatible.push_back(0);
                }
            }
            else
            {
                for (j = 0; j < iIChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
            }
        }

        if (rkIAttr.HasNormal())
        {
            iIChannels = rkIAttr.GetNormalChannels();
            iVBChannels = m_kAttributes.GetNormalChannels();
            puiData = (unsigned int*)NormalTuple(i);
            if (iVBChannels < iIChannels)
            {
                for (j = 0; j < iVBChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
                for (j = iVBChannels; j < iIChannels; j++)
                {
                    // Fill with 0 so that the w-component is compatible with
                    // a homogeneous vector.
                    kCompatible.push_back(0);
                }
            }
            else
            {
                for (j = 0; j < iIChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
            }
        }

        for (iUnit = 0; iUnit < (int)rkIAttr.GetMaxColors(); iUnit++)
        {
            if (rkIAttr.HasColor(iUnit))
            {
                unsigned int auiColor[4], uiPackColor, uiValue;
                float fValue;

                iIChannels = rkIAttr.GetColorChannels(iUnit);
                iVBChannels = m_kAttributes.GetColorChannels(iUnit);
                puiData = (unsigned int*)ColorTuple(iUnit,i);
                if (iVBChannels < iIChannels)
                {
                    for (j = 0; j < iVBChannels; j++)
                    {
                        kCompatible.push_back(*puiData++);
                    }
                    for (j = iVBChannels; j < iIChannels; j++)
                    {
                        // Fill with 1 so that the a-component is compatible
                        // with an opaque color.
                        kCompatible.push_back(*puiOne);
                    }
                    if (bPackARGB)
                    {
                        for (j = iIChannels; j < 4; j++)
                        {
                            // Fill with 1 so that the a-component is
                            // compatible with an opaque color.
                            kCompatible.push_back(*puiOne);
                        }

                        // Map from [0,1] to [0,255].
                        for (j = 3; j >= 0; j--)
                        {
                            uiValue = kCompatible.back();
                            fValue = *(float*)&uiValue;
                            auiColor[j] = (unsigned int)(255.0f*fValue);
                            kCompatible.pop_back();
                        }

                        uiPackColor =
                            (auiColor[2]      ) |  // blue
                            (auiColor[1] <<  8) |  // green
                            (auiColor[0] << 16) |  // red
                            (auiColor[3] << 24);   // alpha

                        kCompatible.push_back(uiPackColor);
                    }
                }
                else
                {
                    for (j = 0; j < iIChannels; j++)
                    {
                        kCompatible.push_back(*puiData++);
                    }
                    if (bPackARGB)
                    {
                        for (j = iIChannels; j < 4; j++)
                        {
                            // Fill with 1 so that the a-component is
                            // compatible with an opaque color.
                            kCompatible.push_back(*puiOne);
                        }

                        // Map from [0,1] to [0,255].
                        for (j = 3; j >= 0; j--)
                        {
                            uiValue = kCompatible.back();
                            fValue = *(float*)&uiValue;
                            auiColor[j] = (unsigned int)(255.0f*fValue);
                            kCompatible.pop_back();
                        }

                        uiPackColor =
                            (auiColor[2]      ) |  // blue
                            (auiColor[1] <<  8) |  // green
                            (auiColor[0] << 16) |  // red
                            (auiColor[3] << 24);   // alpha

                        kCompatible.push_back(uiPackColor);
                    }
                }
            }
        }

        if (rkIAttr.HasFog())
        {
            iIChannels = rkIAttr.GetFogChannels();
            iVBChannels = m_kAttributes.GetFogChannels();
            puiData = (unsigned int*)FogTuple(i);
            if (iVBChannels < iIChannels)
            {
                for (j = 0; j < iVBChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
                for (j = iVBChannels; j < iIChannels; j++)
                {
                    kCompatible.push_back(0);
                }
            }
            else
            {
                for (j = 0; j < iIChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
            }
        }

        if (rkIAttr.HasPSize())
        {
            iIChannels = rkIAttr.GetPSizeChannels();
            iVBChannels = m_kAttributes.GetPSizeChannels();
            puiData = (unsigned int*)PSizeTuple(i);
            if (iVBChannels < iIChannels)
            {
                for (j = 0; j < iVBChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
                for (j = iVBChannels; j < iIChannels; j++)
                {
                    kCompatible.push_back(0);
                }
            }
            else
            {
                for (j = 0; j < iIChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
            }
        }

        if (rkIAttr.HasBlendIndices())
        {
            iIChannels = rkIAttr.GetBlendIndicesChannels();
            iVBChannels = m_kAttributes.GetBlendIndicesChannels();
            puiData = (unsigned int*)BlendIndicesTuple(i);
            if (iVBChannels < iIChannels)
            {
                for (j = 0; j < iVBChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
                for (j = iVBChannels; j < iIChannels; j++)
                {
                    kCompatible.push_back(0);
                }
            }
            else
            {
                for (j = 0; j < iIChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
            }
        }

        for (iUnit = 0; iUnit < (int)rkIAttr.GetMaxTCoords(); iUnit++)
        {
            if (rkIAttr.HasTCoord(iUnit))
            {
                iIChannels = rkIAttr.GetTCoordChannels(iUnit);
                iVBChannels = m_kAttributes.GetTCoordChannels(iUnit);
                puiData = (unsigned int*)TCoordTuple(iUnit,i);
                if (iVBChannels < iIChannels)
                {
                    for (j = 0; j < iVBChannels; j++)
                    {
                        kCompatible.push_back(*puiData++);
                    }
                    for (j = iVBChannels; j < iIChannels; j++)
                    {
                        // Fill with 0 so that the components are compatible
                        // with a higher-dimensional image embedded in a
                        // lower-dimensional one.
                        kCompatible.push_back(0);
                    }
                }
                else
                {
                    for (j = 0; j < iIChannels; j++)
                    {
                        kCompatible.push_back(*puiData++);
                    }
                }
            }
        }

        if (rkIAttr.HasTangent())
        {
            iIChannels = rkIAttr.GetTangentChannels();
            iVBChannels = m_kAttributes.GetTangentChannels();
            puiData = (unsigned int*)TangentTuple(i);
            if (iVBChannels < iIChannels)
            {
                for (j = 0; j < iVBChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
                for (j = iVBChannels; j < iIChannels; j++)
                {
                    // Fill with 0 so that the w-component is compatible with
                    // a homogeneous vector.
                    kCompatible.push_back(0);
                }
            }
            else
            {
                for (j = 0; j < iIChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
            }
        }

        if (rkIAttr.HasBitangent())
        {
            iIChannels = rkIAttr.GetBitangentChannels();
            iVBChannels = m_kAttributes.GetBitangentChannels();
            puiData = (unsigned int*)BitangentTuple(i);
            if (iVBChannels < iIChannels)
            {
                for (j = 0; j < iVBChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
                for (j = iVBChannels; j < iIChannels; j++)
                {
                    // Fill with 0 so that the w-component is compatible with
                    // a homogeneous vector.
                    kCompatible.push_back(0);
                }
            }
            else
            {
                for (j = 0; j < iIChannels; j++)
                {
                    kCompatible.push_back(*puiData++);
                }
            }
        }
    }

    riChannels = (int)kCompatible.size();
    if (!rafOut)
    {
        rafOut = new float[riChannels];
    }
    size_t uiSize = riChannels*sizeof(float);
    System::Memcpy(rafOut,uiSize,&kCompatible.front(),uiSize);
}
//---------------------------------------------------------------------------------------------------
void VertexBuffer::PrintToFile(const char* acFilename)
{
	std::ofstream kOStr(acFilename);
	kOStr	<< "--------------------------------\n"
			<< "Vertex Buffer Data Begin\n"
			<< "--------------------------------\n";
	int iIndex = 0;
	if (m_kAttributes.HasPosition())
	{
		kOStr	<< "---------------------------\n"
				<< "Position Data Begin\n"
				<< "---------------------------\n";		
		for (int i = 0; i < m_iVertexQuantity; i++)
		{
			// Position data
			iIndex = m_iVertexSize*i + m_kAttributes.GetPositionOffset();
		
			kOStr << i << "	: ("
				  << (m_afData+iIndex)[0]   << ", "
				  << (m_afData+iIndex)[1] << ", "
				  << (m_afData+iIndex)[2] << ")\n";
		}
		kOStr	<< "---------------------------\n"
				<< "Position Data End\n"
				<< "---------------------------\n";	
	}
	
	if (m_kAttributes.HasBlendWeight())
	{
		kOStr	<< "---------------------------\n"
				<< "BlendWeight Data Begin\n"
				<< "---------------------------\n";		
		for (int i = 0; i < m_iVertexQuantity; i++)
		{
			// Blend weight data
			iIndex = m_iVertexSize*i + m_kAttributes.GetBlendWeightOffset();
		
			kOStr << i << "	: ("
				  << (m_afData+iIndex)[0]   << ", "
				  << (m_afData+iIndex)[1] << ", "
				  << (m_afData+iIndex)[2] << ")\n";
		}
		kOStr	<< "---------------------------\n"
				<< "BlendWeight Data End\n"
				<< "---------------------------\n";	
	}

	if (m_kAttributes.HasNormal())
	{
		// Normal data
		kOStr	<< "---------------------------\n"
				<< "Normal Data Begin\n"
				<< "---------------------------\n";	
		for (int i = 0; i < m_iVertexQuantity; i++)
		{
			iIndex = m_iVertexSize*i + m_kAttributes.GetNormalOffset();
		
			kOStr << i << "	: ("
				  << (m_afData+iIndex)[0]   << ", "
				  << (m_afData+iIndex)[1] << ", "
				  << (m_afData+iIndex)[2] << ")\n";
		}
		kOStr	<< "---------------------------\n"
				<< "Normal Data End\n"
				<< "---------------------------\n";	
	}

	if (m_kAttributes.HasBlendIndices())
	{
		kOStr	<< "---------------------------\n"
				<< "BlendIndices Data Begin\n"
				<< "---------------------------\n";		
		for (int i = 0; i < m_iVertexQuantity; i++)
		{
			// BlendIndices data
			iIndex = m_iVertexSize*i + m_kAttributes.GetBlendIndicesOffset();
		
			kOStr << i << "	: ("
				  << (m_afData+iIndex)[0]   << ", "
				  << (m_afData+iIndex)[1] << ", "
				  << (m_afData+iIndex)[2] << ")\n";
		}
		kOStr	<< "---------------------------\n"
				<< "BlendIndices Data End\n"
				<< "---------------------------\n";	
	}

	if (m_kAttributes.GetMaxTCoords() > 0)
	{
		// Texture coordinate data
		kOStr	<< "---------------------------\n"
				<< "TexCoords Data Begin\n"
				<< "---------------------------\n";	
		for (int i = 0; i < m_kAttributes.GetMaxTCoords(); i++)
		{
			kOStr	<< "---------------------------\n"
					<< "TCoord channel : " << i << std::endl
					<< "---------------------------\n";
			for (int j = 0; j < m_iVertexQuantity; j++)
			{
				iIndex = m_iVertexSize*j + m_kAttributes.GetTCoordOffset(i);
				kOStr << j << "	: (";
				for (int k = 0; k < m_kAttributes.GetTCoordChannels(i); k++)
				{
					kOStr << (m_afData+iIndex)[k] << ",";
				}
				kOStr << ")\n";
			}
		}
		kOStr	<< "---------------------------\n"
				<< "TexCoords Data End\n"
				<< "---------------------------\n";		
	}

	kOStr	<< "--------------------------------\n"
			<< "Vertex Buffer Data End\n"
			<< "--------------------------------\n";
	kOStr.close();
}
//---------------------------------------------------------------------------------------------------